from sqlalchemy import inspect, Column, Integer, String, SmallInteger, orm
from werkzeug.security import generate_password_hash, check_password_hash

from app.libs.error_code import AuthFailed
from app.models.base import Base, db, MixinJSONSerializer
import datetime


# class User(MixinJSONSerializer,Base): # 使用了MixinJSONSerializer 模型里的 keys方法也可以省略
class User(Base):
    id = Column(Integer, primary_key=True)
    email = Column(String(24), unique=True, nullable=False)
    nickname = Column(String(24), unique=True)
    auth = Column(SmallInteger, default=1)  #  1：普通用户  2：管理员
    _password = Column('password', String(128))

    # 转成字典的时候会进入到这个方法，获取key值, 这里是需要序列化的字段
    def keys(self): # 如果想要省略keys方法可以让打当前模型先继承base.py 中的MixinJSONSerializer类
        return ['id', 'email', 'nickname', 'auth']

    # 本来还有一个 __getitem__ 方法，统一放到base.py中去了
    # def __getitem__(self, item):
    #     return getattr(self, item)

    @property
    def password(self):
        return self._password


    # 密码加密
    @password.setter
    def password(self, raw):
        self._password = generate_password_hash(raw)

    # 根据email 注册用户
    @staticmethod
    def register_by_email(nickname, account, secret):
        with db.auto_commit():
            user = User()
            user.nickname = nickname
            user.email = account
            user.password = secret
            db.session.add(user)


    # 用于登录时候验证用户是否存在， 在app/api/v1/token.py的create_token方法中用到
    @staticmethod
    def verify(email, password):
        # user = User.query.filter_by(email=email).first()
        # if not user:  # 用户不存在
        #     raise AuthFailed(msg="用户名不存在")
        # if not user.check_password(password):  # 密码错误
        #     raise AuthFailed(msg="密码错误")
        # return {'uid': user.id}

        user = User.query.filter_by(email=email).first_or_404()
        if not user.check_password(password): # 密码错误
            raise AuthFailed()
        scope = 'AdminScope' if user.auth == 2 else 'UserScope'  # auth =2 代表管理员; auth =1 代表普通用户，
        # 这里scope为什么要具体使用AdminScope、UserScope 是为了后面可以根据这个字符串 拿到对应名字的类对象， 具体可见app/libs/scope.py的is_in_scope方法

        return {'uid': user.id, 'scope': scope}

    # 检查密码是否正确
    def check_password(self, raw):
        if not self._password:
            return False
        return check_password_hash(self._password, raw)  #返回True or False， 如果是True 代表密码一致

    # def _set_fields(self):
    #     # self._exclude = ['_password']
    #     self._fields = ['_password', 'nickname']
